﻿using System;
using Notoric.Commanding.CommandBase;

namespace Notoric.ViewModel
{
    /// <summary>
    /// An undoable command for inserting a new staff descriptor into a part descriptor.
    /// </summary>
    public class InsertStaffDescriptorCommand : UndoableCommandBase
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="InsertStaffDescriptorCommand"/> class.
        /// </summary>
        /// <param name="undoStack">The undo command stack</param>
        /// <param name="redoStack">The redo command stack</param>
        public InsertStaffDescriptorCommand(CommandStack undoStack, CommandStack redoStack)
            : base(undoStack, redoStack)
        {
            AddParameter<double>("DefaultHeight", ParameterDirection.In);
            AddParameter<int>("Index", ParameterDirection.In);
            AddParameter<byte>("Lines", ParameterDirection.In);
            AddParameter<Elements.PartDescriptor>("PartDescriptor", ParameterDirection.In);

            Name = "Add Staff";
        }

        #endregion

        #region Command Logic

        /// <inheritdoc/>
        protected override void CommandOperation(object parameter)
        {
            var modelDescriptor = PartDescriptor.AdaptedElement as Model.Elements.PartDescriptorElement;

            var cData = modelDescriptor.FindCustomData<Model.Elements.CWNotation.CWPartData>();
            if (cData == null)
            {
                cData = new Model.Elements.CWNotation.CWPartData(
                    modelDescriptor.PackagePart as Model.Packaging.CompositionPart,
                    modelDescriptor
                    );
                modelDescriptor.CustomData.Add(cData);
            }

            createdDescriptor = cData.AddStaffDescriptor(Lines, Index, DefaultHeight);

            modelDescriptor.PackagePart.Package.IsModified = true;
        }

        /// <inheritdoc/>
        protected override void RedoOperation()
        {
            var modelDescriptor = PartDescriptor.AdaptedElement as Model.Elements.PartDescriptorElement;
            var cData = modelDescriptor.FindCustomData<Model.Elements.CWNotation.CWPartData>();
            cData.AddExistingStaffDescriptor(createdDescriptor, Index);

            PartDescriptor.FindOwner<Elements.Project>().IsModified = true;
        }

        /// <inheritdoc/>
        protected override void UndoOperation()
        {
            var modelDescriptor = PartDescriptor.AdaptedElement as Model.Elements.PartDescriptorElement;
            var cData = modelDescriptor.FindCustomData<Model.Elements.CWNotation.CWPartData>();
            cData.RemoveStaffDescriptor(createdDescriptor);

            PartDescriptor.FindOwner<Elements.Project>().IsModified = true;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the default height of the staff.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The default height in centimeters of the described staff.<br/>
        /// This property wraps the "DefaultHeight" command parameter.
        /// </para>
        /// </value>
        public double DefaultHeight
        {
            get { return GetParameterValue<double>("DefaultHeight"); }
            set { SetParameterValue<double>("DefaultHeight", value); }
        }

        /// <summary>
        /// Gets or sets the index of the staff.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The index of the described staff in the part.<br/>
        /// This property wraps the "Index" command parameter.
        /// </para>
        /// </value>
        public int Index
        {
            get { return GetParameterValue<int>("Index"); }
            set { SetParameterValue<int>("Index", value); }
        }

        /// <summary>
        /// Gets or sets the number of the staff lines.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Byte"/>
        /// </para>
        /// <para>
        /// The number of the staff lines.<br/>
        /// This property wraps the "Lines" command parameter.
        /// </para>
        /// </value>
        public byte Lines
        {
            get { return GetParameterValue<byte>("Lines"); }
            set { SetParameterValue<byte>("Lines", value); }
        }

        /// <summary>
        /// Gets or sets the descriptor of the part where the staff descriptor will be created.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Elements.PartDescriptor"/>
        /// </para>
        /// <para>
        /// The descriptor of the part in which the new staff descriptor will be created.<br/>
        /// This property wraps the "PartDescriptor" command parameter.
        /// </para>
        /// </value>
        public Elements.PartDescriptor PartDescriptor
        {
            get { return GetParameterValue<Elements.PartDescriptor>("PartDescriptor"); }
            set { SetParameterValue<Elements.PartDescriptor>("PartDescriptor", value); }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the created descriptor.
        /// </summary>
        private Model.Elements.CWNotation.StaffDescriptor createdDescriptor;

        #endregion
    }
}
